#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace YPFramework
{

    [CustomEditor(typeof(UIBase), true)]
    public class UIEditor : Editor
    {
        private static UIEditor Instance;
        private UIBase _uiBase;
        private readonly HashSet<int> _remove = new HashSet<int>();
        private static readonly Dictionary<string, Object> _add = new ();
        
        private void OnEnable()
        {
            Instance = this;
            _uiBase = (UIBase)target;
        }

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            EditorGUILayout.Space();
            var dataProperty = serializedObject.FindProperty("list");
            
            if (_add.Count > 0)
            {
                foreach (var addPair in _add)
                {
                    AddReference(dataProperty, addPair.Key, addPair.Value);
                    EditorUtility.SetDirty(_uiBase);
                }
                _add.Clear();
            }
            
            GUILayout.BeginHorizontal();
            
            // 添加引用
            if (GUILayout.Button("Add"))
            {
                AddReference(dataProperty, Guid.NewGuid().GetHashCode().ToString(), null);
            }
            
            // 清空引用
            if (GUILayout.Button("Clear"))
            {
                dataProperty.ClearArray();
                EditorUtility.SetDirty(this);
                serializedObject.ApplyModifiedProperties();
                serializedObject.UpdateIfRequiredOrScript();
            }

            
            // 删除空引用
            if (GUILayout.Button("Delete Empty"))
            {
                for (var i = dataProperty.arraySize - 1; i >= 0; i--)
                {
                    var gameObjectProperty = dataProperty.GetArrayElementAtIndex(i).FindPropertyRelative("gameObject");

                    if (gameObjectProperty.objectReferenceValue != null)
                    {
                        continue;
                    }
                    
                    dataProperty.DeleteArrayElementAtIndex(i);
                    EditorUtility.SetDirty(_uiBase);
                    serializedObject.ApplyModifiedProperties();
                    serializedObject.UpdateIfRequiredOrScript();
                }
            }
            
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();

            if (GUILayout.Button(new GUIContent("Generate Code")))
            {
                Generate(dataProperty);
            }
            
            GUILayout.EndHorizontal();
            
            // 展示引用列表
            for (var i = _uiBase.list.Count - 1; i >= 0; i--)
            {
                GUILayout.BeginHorizontal();
                var property = dataProperty.GetArrayElementAtIndex(i).FindPropertyRelative("key");
                EditorGUILayout.TextField(property.stringValue, GUILayout.Width(150));
                property = dataProperty.GetArrayElementAtIndex(i).FindPropertyRelative("gameObject");
                property.objectReferenceValue = EditorGUILayout.ObjectField(property.objectReferenceValue, typeof(Object), true);
                
                if (GUILayout.Button("X"))
                {
                    _remove.Add(i);
                }
                
                GUILayout.EndHorizontal();
            }
            
            var eventType = Event.current.type;
            
            if (eventType == EventType.DragUpdated || eventType == EventType.DragPerform)
            {
                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
            
                if (eventType == EventType.DragPerform)
                {
                    DragAndDrop.AcceptDrag();
                    
                    foreach (var o in DragAndDrop.objectReferences)
                    {
                        AddReference(dataProperty, o.name, o);
                    }
                }
            
                Event.current.Use();
            }

            if (_remove.Count > 0)
            {
                foreach (var removeIndex in _remove)
                {
                    dataProperty.DeleteArrayElementAtIndex(removeIndex);
                }
                
                _remove.Clear();
            }

            serializedObject.ApplyModifiedProperties();
            serializedObject.UpdateIfRequiredOrScript();
        }
        
        private void AddReference(SerializedProperty dataProperty, string key, Object obj)
        {
            var index = dataProperty.arraySize;
            dataProperty.InsertArrayElementAtIndex(index);
            var element = dataProperty.GetArrayElementAtIndex(index);
            element.FindPropertyRelative("key").stringValue = key;
            
            // 开启自动检测
            if(obj == null) return;
            
            if(obj.name.StartsWith("Txt_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<TMPro.TextMeshProUGUI>();
            else if(obj.name.StartsWith("Btn_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<UnityEngine.UI.Button>();
            else if(obj.name.EndsWith("Ori"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<UnityEngine.Transform>();
            else if(obj.name.StartsWith("Img_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<UnityEngine.UI.Image>();
            else if(obj.name.StartsWith("Sli_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<UnityEngine.UI.Slider>();
            else if(obj.name.StartsWith("Tog_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<UnityEngine.UI.Toggle>();
            else if(obj.name.StartsWith("Dro_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<UnityEngine.UI.Dropdown>();
            else if(obj.name.StartsWith("Inp_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<TMPro.TMP_InputField>();
            else if(obj.name.StartsWith("List_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<SuperScrollView.LoopListView2>();
            else if(obj.name.StartsWith("Grid_"))
                element.FindPropertyRelative("gameObject").objectReferenceValue = ((GameObject)obj).GetComponent<SuperScrollView.LoopGridView>();
            else
                element.FindPropertyRelative("gameObject").objectReferenceValue = obj;
        }

        private static void AddReference(string key, Object obj)
        {
            if(!_add.ContainsKey(key))
                _add.Add(key, obj);
            else
                Debug.LogError("请勿重复添加!");
            Instance?.OnInspectorGUI();
        }

        private void Generate(SerializedProperty dataProperty)
        {
            var setting = Resources.Load<CPToolSettings>("CPToolSettings");
            if (setting == null)
            {
                Debug.LogError($"请在Resources目录右键创建CPToolSettings，并填写UI代码生成路径!");
                return;
            }
            var generatePath = setting.UIGeneratePath;

            if (!Directory.Exists($"{generatePath}"))
            {
                Directory.CreateDirectory($"{generatePath}");
                AssetDatabase.Refresh();
                Debug.LogError($"目录{generatePath}不存在，自动创建,再次点击Generate生成代码!");
                return;
            }

            if (string.IsNullOrEmpty(_uiBase.gameObject.name))
            {
                EditorUtility.DisplayDialog("Generate Code", $"assetName is null", "OK");
                return;
            }
            

            var createStr = new List<string>();
            var propertyStr = new List<string>();

            for (var i = _uiBase.list.Count - 1; i >= 0; i--)
            {
                var keyProperty = dataProperty.GetArrayElementAtIndex(i).FindPropertyRelative("key");
                var gameObjectProperty = dataProperty.GetArrayElementAtIndex(i).FindPropertyRelative("gameObject");
                var refName = gameObjectProperty.objectReferenceValue.GetType().FullName;
                var gameObjectName = Regex.Replace(keyProperty.stringValue, @"\s+", "");
                propertyStr.Add($"\t\t[HideInInspector] public {refName} {gameObjectName};");
                createStr.Add($"\t\t\t{gameObjectName} = GetReference<{refName}>(\"{keyProperty.stringValue}\");");
            }

            var sb = new StringBuilder();
            
            sb.AppendLine("using UnityEngine;");
            sb.AppendLine("using YPFramework;");
            sb.AppendLine($"\tpublic partial class {_uiBase.gameObject.name}\n\t{{");
            
            foreach (var property in propertyStr)
            {
                sb.AppendLine(property);
            }

            sb.AppendLine("\n\t\tprotected override void OnCreate()\n\t\t{");

            foreach (var str in createStr)
            {
                sb.AppendLine(str);
            }

            sb.AppendLine("\t\t}");
            sb.AppendLine("\t}");

            var combinePath = Path.Combine(generatePath, $"{_uiBase.gameObject.name}.View.cs");
            using var entityStreamWriter = new StreamWriter(combinePath);
            entityStreamWriter.Write(sb.ToString());
            AssetDatabase.Refresh();
            Debug.Log($"代码生成位置:{combinePath}");
        }
        
        [InitializeOnLoadMethod]
        private static void CPToolUIExt()
        {
            EditorApplication.hierarchyWindowItemOnGUI = (instanceID, selectionRect) =>
            {
                var obj = (GameObject)EditorUtility.InstanceIDToObject(instanceID);
                if (obj != null && obj.GetComponent<RectTransform>() != null)
                {
                    var basePanel = obj.transform.root.GetComponentInChildren<UIBase>();
                    if (basePanel == null) return;
                    if (!basePanel.ContainReference(obj.name))
                    {
                        int width = 30;
                        var btnRect = selectionRect;
                        btnRect.x += selectionRect.width - width / 2f;
                        btnRect.width = width;
                        if (GUI.Button(btnRect,"+"))
                        {
                            AddReference(obj.name, obj);
                        }
                    }
                    else
                    {
                        var style = new GUIStyle();
                        style.fontStyle = FontStyle.Bold;
                        style.normal.textColor = Color.green;
                        float width = GUI.skin.label.CalcSize(new GUIContent(obj.name)).x - 10;
                        var labelRect = selectionRect;
                        labelRect.x += selectionRect.width - width;
                        labelRect.width = width;
                        GUI.Label(labelRect, obj.name, style);
                    }
                }
            };
        }
    }
}
#endif